/* Elise Eiden
Taryn Green
Kevin McGinn

Software Engineering
Networking Feasibility Study
server.cpp

Reference: The Boost "daytime" example
*/

#include  <cctype>
#include <iostream>
#include <string>
#include <cstdlib>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>

using boost::asio::ip::udp;

class udp_server {
public: 
  //constructor
  udp_server(boost::asio::io_service & io_service)
    : socket_(io_service, udp::endpoint(udp::v4(), 13)) {
	std::cout<<"Constructing a udp_server\n";
    cube_x = 0;
    cube_y = 0;
    cube_z = 0;
    start_receive();
  }

private:

  //helper functions

  //start listening for client messages
  void start_receive() {
    socket_.async_receive_from( boost::asio::buffer(recv_buffer_), remote_endpoint_, boost::bind(&udp_server::handle_receive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
	std::cout<<"Start receiving\n";

  }

  //receive client messages
  void handle_receive(const boost::system::error_code & error, std::size_t) {
	std::cout<<"Starting to handle a receive\n";

    //no error or the error was about message size
	if(error)
		std::cout<< "error" << std::endl;
    if(!error || error == boost::asio::error::message_size) {

      for(int i = 0; i < recv_buffer_.size(); i++) {
	switch(recv_buffer_[i]) {
	case 'w':
	  cube_y++;
	  break;
	case 's':
	  cube_y--;
	  break;
	case 'd':
	  cube_x++;
	  break;
	case 'a':
	  cube_x--;
	  break;
	case 'e':
	  cube_z++;
	  break;
	case 'q':
	  cube_z--;
	  break;
	default:
	  break;
	}
      }


      //have the server print out its current state of the cube
      //for debugging resources
      std::cout << "x: " << cube_x << "y: " << cube_y << "z: " << cube_z << std::endl;

      //make the message to send
      std::string cube_position;
      //note: this is a temporary fix until we make a cube class
      //with a serialize function
      
      //char buf [33];

      cube_position.append("x: ");
      //      itoa(cube_x, buf, 10);
      //cube_position.append(buf);
      cube_position.append(" y: ");
      //itoa(cube_y, buf, 10);
      //cube_position.append(buf);
      cube_position.append(" z: ");
      //itoa(cube_z, buf, 10);
      //cube_position.append(buf);

      boost::shared_ptr<std::string> message (new std::string(cube_position));

      //sends a message back to client
      socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_, boost::bind(&udp_server::handle_send, this, message, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

      //listen for more client requests
      start_receive();
    }
  }

  //handles sending the message
  //not implemented yet? not necessary?
  void handle_send(boost::shared_ptr<std::string>, const boost::system::error_code &, std::size_t) {
  }

  //data members
  udp::socket socket_;
  udp::endpoint remote_endpoint_;
  boost::array<char, 1> recv_buffer_;


  //NOTE: these variables should eventually be moved to a separate class object
  int cube_x;
  int cube_y;
  int cube_z;

};

int main() {
  try{
	std::cout<<"First line of main\n";
    //create io service
    boost::asio::io_service io_service;
	std::cout<<"Started service\n";
    //link to server object
    udp_server server(io_service);
	std::cout<<"Link to server\n";

    //run the service
    size_t x = io_service.run();
	std::cout<<x;
	std::cout<<"Run Service \n";

  }
  catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
  }

  return 0;
}
